
public class Args<T1> { }
public class Args<T1, T2> { }
public class Args<T1, T2, T3> { }
public class Args<T1, T2, T3, T4> { }
public class Args<T1, T2, T3, T4, T5> { }
public class Args<T1, T2, T3, T4, T5, T6> { }
public class Args<T1, T2, T3, T4, T5, T6, T7> { }
public class Args<T1, T2, T3, T4, T5, T6, T7, T8> { }
public class Args<T1, T2, T3, T4, T5, T6, T7, T8, T9> { }

public class With<T1> { public static Args<T1> Args { get { return null; } } }
public class With<T1, T2> { public static Args<T1, T2> Args { get { return null; } } }
public class With<T1, T2, T3> { public static Args<T1, T2, T3> Args { get { return null; } } }
public class With<T1, T2, T3, T4> { public static Args<T1, T2, T3, T4> Args { get { return null; } } }
public class With<T1, T2, T3, T4, T5> { public static Args<T1, T2, T3, T4, T5> Args { get { return null; } } }
public class With<T1, T2, T3, T4, T5, T6> { public static Args<T1, T2, T3, T4, T5, T6> Args { get { return null; } } }
public class With<T1, T2, T3, T4, T5, T6, T7> { public static Args<T1, T2, T3, T4, T5, T6, T7> Args { get { return null; } } }
public class With<T1, T2, T3, T4, T5, T6, T7, T8> { public static Args<T1, T2, T3, T4, T5, T6, T7, T8> Args { get { return null; } } }
public class With<T1, T2, T3, T4, T5, T6, T7, T8, T9> { public static Args<T1, T2, T3, T4, T5, T6, T7, T8, T9> Args { get { return null; } } }

namespace Internals
{
    using System;
    using System.Collections;
    using System.Collections.Generic;

    public class StubHelper
    {
        private readonly Dictionary<string, List<ExecuteInfo>> _executeInfo = new Dictionary<string, List<ExecuteInfo>>();
        private readonly List<StubInvocation> _invocations = new List<StubInvocation>();

        public void SetMethodToReturn(string methodName, object[] args, object result)
        {
            SetExecuteInfo(methodName, args, result, null, null);
        }

        public void SetMethodToThrow(string methodName, object[] args, Exception e)
        {
            SetExecuteInfo(methodName, args, null, e, null);
        }

        public void SetMethodToInvoke(string methodName, object[] args, Delegate d)
        {
            SetExecuteInfo(methodName, args, null, null, d);
        }

        private void SetExecuteInfo(string methodName, object[] args, object result, Exception e, Delegate d)
        {
            if (!_executeInfo.ContainsKey(methodName))
            {
                _executeInfo[methodName] = new List<ExecuteInfo>();
            }

            ExecuteInfo info = new ExecuteInfo();
            info.With = args;
            info.Return = result;
            info.Throw = e;
            info.Invoke = d;

            _executeInfo[methodName].Insert(0, info);
        }

        public void ExecuteAction(string methodName, params object[] args)
        {
            AddInvocation(methodName, args);

            ExecuteInfo info = GetExecuteInfo(methodName, args);

            if (info != null)
            {
                if (info.Invoke != null)
                {
                    info.Invoke.DynamicInvoke(args);
                }

                if (info.Throw != null)
                {
                    throw info.Throw;
                }
            }
        }

        public T ExecuteFunc<T>(string methodName, params object[] args)
        {
            AddInvocation(methodName, args);

            ExecuteInfo info = GetExecuteInfo(methodName, args);

            if (info != null)
            {
                if (info.Invoke != null)
                {
                    return (T)info.Invoke.DynamicInvoke(args);
                }

                if (info.Throw != null)
                {
                    throw info.Throw;
                }

                return (T)info.Return;
            }

            return default(T);
        }

        public void ExecutePropertySetter(string setterName, string getterName, object value, params object[] args)
        {
            ExecuteAction(setterName, args);

            if (getterName != null)
            {
                SetMethodToReturn(getterName, args, value);
            }
        }

        public T ExecutePropertyGetter<T>(string methodName, params object[] args)
        {
            return ExecuteFunc<T>(methodName, args);
        }

        private ExecuteInfo GetExecuteInfo(string methodName, object[] args)
        {
            if (_executeInfo.ContainsKey(methodName))
            {
                foreach (ExecuteInfo info in _executeInfo[methodName])
                {
                    if (info.With == null || ArgumentsMatch(args, info.With))
                    {
                        return info;
                    }
                }
            }

            return null;
        }

        private bool ArgumentsMatch(object[] a, object[] b)
        {
            if (a.Length != b.Length)
            {
                return false;
            }

            for (int i = 0; i < b.Length; i++)
            {
                if (!ObjectsAreEqual(a[i], b[i]))
                {
                    return false;
                }
            }

            return true;
        }

        private bool ObjectsAreEqual(object a, object b)
        {
            if (Equals(a, b))
            {
                return true;
            }

            // TODO: Check for IEquatable?

            return EnumerablesAreEqual(a, b);
        }

        private bool EnumerablesAreEqual(object a, object b)
        {
            IEnumerable aEnumerable = a as IEnumerable;
            IEnumerable bEnumerable = b as IEnumerable;

            if (aEnumerable != null && bEnumerable != null)
            {
                IEnumerator aEnumerator = aEnumerable.GetEnumerator();
                IEnumerator bEnumerator = bEnumerable.GetEnumerator();

                bool aHasMore = aEnumerator.MoveNext();
                bool bHasMore = bEnumerator.MoveNext();

                while (aHasMore && bHasMore)
                {
                    if (!ObjectsAreEqual(aEnumerator.Current, bEnumerator.Current))
                    {
                        return false;
                    }

                    aHasMore = aEnumerator.MoveNext();
                    bHasMore = bEnumerator.MoveNext();
                }

                return !(aHasMore || bHasMore);
            }

            return false;
        }

        private void AddInvocation(string methodName, object[] args)
        {
            StubInvocation invocation = new StubInvocation();
            invocation.MethodName = methodName;
            invocation.Args = args;
            _invocations.Add(invocation);
        }

        public List<StubInvocation> GetInvocations(string methodName)
        {
            List<StubInvocation> invocations = new List<StubInvocation>();

            foreach (StubInvocation invocation in _invocations)
            {
                if (invocation.MethodName == methodName)
                {
                    invocations.Add(invocation);
                }
            }

            return invocations;
        }

        public StubInvocation GetLastInvocation(string methodName)
        {
            for (int i = _invocations.Count - 1; i >= 0; i--)
            {
                if (_invocations[i].MethodName == methodName)
                {
                    return _invocations[i];
                }
            }

            return null;
        }

        private class ExecuteInfo
        {
            public object[] With;
            public object Return;
            public Exception Throw;
            public Delegate Invoke;
        }
    }

    public class StubInvocation
    {
        public string MethodName;
        public object[] Args;
    }

    public class ActionMethodBase
    {
        protected StubHelper _stubHelper;
        protected string _methodName;

        public ActionMethodBase(StubHelper stubHelper, string methodName)
        {
            _stubHelper = stubHelper;
            _methodName = methodName;
        }

        public void ToThrow(Exception e)
        {
            _stubHelper.SetMethodToThrow(_methodName, null, e);
        }

        public int GetInvocationCount()
        {
            return _stubHelper.GetInvocations(_methodName).Count;
        }
    }

    public class ActionMethod : ActionMethodBase
    {
        public ActionMethod(StubHelper stubHelper, string methodName) : base(stubHelper, methodName) { }

        public void ToDo(Action d)
        {
            _stubHelper.SetMethodToInvoke(_methodName, null, d);
        }
    }

    public class ActionMethod<T1> : ActionMethodBase
    {
        public ActionMethod(StubHelper stubHelper, string methodName) : base(stubHelper, methodName) { }

        public void ToDo(Action<T1> d)
        {
            _stubHelper.SetMethodToInvoke(_methodName, null, d);
        }

        public void GetLastArgs(out T1 arg1)
        {
            StubInvocation lastInvocation = _stubHelper.GetLastInvocation(_methodName);
            arg1 = (T1)lastInvocation.Args[0];
        }
    }

    public class ActionMethod<T1, T2> : ActionMethodBase
    {
        public ActionMethod(StubHelper stubHelper, string methodName) : base(stubHelper, methodName) { }

        public void ToDo(Action<T1, T2> d)
        {
            _stubHelper.SetMethodToInvoke(_methodName, null, d);
        }

        public void GetLastArgs(out T1 arg1, out T2 arg2)
        {
            StubInvocation lastInvocation = _stubHelper.GetLastInvocation(_methodName);
            arg1 = (T1)lastInvocation.Args[0];
            arg2 = (T2)lastInvocation.Args[1];
        }
    }

    public class ActionMethod<T1, T2, T3> : ActionMethodBase
    {
        public ActionMethod(StubHelper stubHelper, string methodName) : base(stubHelper, methodName) { }

        public void ToDo(Action<T1, T2, T3> d)
        {
            _stubHelper.SetMethodToInvoke(_methodName, null, d);
        }

        public void GetLastArgs(out T1 arg1, out T2 arg2, out T3 arg3)
        {
            StubInvocation lastInvocation = _stubHelper.GetLastInvocation(_methodName);
            arg1 = (T1)lastInvocation.Args[0];
            arg2 = (T2)lastInvocation.Args[1];
            arg3 = (T3)lastInvocation.Args[2];
        }
    }

    public class ActionMethod<T1, T2, T3, T4> : ActionMethodBase
    {
        public ActionMethod(StubHelper stubHelper, string methodName) : base(stubHelper, methodName) { }

        public void ToDo(Action<T1, T2, T3, T4> d)
        {
            _stubHelper.SetMethodToInvoke(_methodName, null, d);
        }

        public void GetLastArgs(out T1 arg1, out T2 arg2, out T3 arg3, out T4 arg4)
        {
            StubInvocation lastInvocation = _stubHelper.GetLastInvocation(_methodName);
            arg1 = (T1)lastInvocation.Args[0];
            arg2 = (T2)lastInvocation.Args[1];
            arg3 = (T3)lastInvocation.Args[2];
            arg4 = (T4)lastInvocation.Args[3];
        }
    }

    public class ActionMethod<T1, T2, T3, T4, T5> : ActionMethodBase
    {
        public ActionMethod(StubHelper stubHelper, string methodName) : base(stubHelper, methodName) { }

        public void ToDo(Action<T1, T2, T3, T4, T5> d)
        {
            _stubHelper.SetMethodToInvoke(_methodName, null, d);
        }

        public void GetLastArgs(out T1 arg1, out T2 arg2, out T3 arg3, out T4 arg4, out T5 arg5)
        {
            StubInvocation lastInvocation = _stubHelper.GetLastInvocation(_methodName);
            arg1 = (T1)lastInvocation.Args[0];
            arg2 = (T2)lastInvocation.Args[1];
            arg3 = (T3)lastInvocation.Args[2];
            arg4 = (T4)lastInvocation.Args[3];
            arg5 = (T5)lastInvocation.Args[4];
        }
    }

    public class ActionMethod<T1, T2, T3, T4, T5, T6> : ActionMethodBase
    {
        public ActionMethod(StubHelper stubHelper, string methodName) : base(stubHelper, methodName) { }

        public void ToDo(Action<T1, T2, T3, T4, T5, T6> d)
        {
            _stubHelper.SetMethodToInvoke(_methodName, null, d);
        }

        public void GetLastArgs(out T1 arg1, out T2 arg2, out T3 arg3, out T4 arg4, out T5 arg5, out T6 arg6)
        {
            StubInvocation lastInvocation = _stubHelper.GetLastInvocation(_methodName);
            arg1 = (T1)lastInvocation.Args[0];
            arg2 = (T2)lastInvocation.Args[1];
            arg3 = (T3)lastInvocation.Args[2];
            arg4 = (T4)lastInvocation.Args[3];
            arg5 = (T5)lastInvocation.Args[4];
            arg6 = (T6)lastInvocation.Args[5];
        }
    }

    public class ActionMethod<T1, T2, T3, T4, T5, T6, T7> : ActionMethodBase
    {
        public ActionMethod(StubHelper stubHelper, string methodName) : base(stubHelper, methodName) { }

        public void ToDo(Action<T1, T2, T3, T4, T5, T6, T7> d)
        {
            _stubHelper.SetMethodToInvoke(_methodName, null, d);
        }

        public void GetLastArgs(out T1 arg1, out T2 arg2, out T3 arg3, out T4 arg4, out T5 arg5, out T6 arg6, out T7 arg7)
        {
            StubInvocation lastInvocation = _stubHelper.GetLastInvocation(_methodName);
            arg1 = (T1)lastInvocation.Args[0];
            arg2 = (T2)lastInvocation.Args[1];
            arg3 = (T3)lastInvocation.Args[2];
            arg4 = (T4)lastInvocation.Args[3];
            arg5 = (T5)lastInvocation.Args[4];
            arg6 = (T6)lastInvocation.Args[5];
            arg7 = (T7)lastInvocation.Args[6];
        }
    }

    public class ActionMethod<T1, T2, T3, T4, T5, T6, T7, T8> : ActionMethodBase
    {
        public ActionMethod(StubHelper stubHelper, string methodName) : base(stubHelper, methodName) { }

        public void ToDo(Action<T1, T2, T3, T4, T5, T6, T7, T8> d)
        {
            _stubHelper.SetMethodToInvoke(_methodName, null, d);
        }

        public void GetLastArgs(out T1 arg1, out T2 arg2, out T3 arg3, out T4 arg4, out T5 arg5, out T6 arg6, out T7 arg7, out T8 arg8)
        {
            StubInvocation lastInvocation = _stubHelper.GetLastInvocation(_methodName);
            arg1 = (T1)lastInvocation.Args[0];
            arg2 = (T2)lastInvocation.Args[1];
            arg3 = (T3)lastInvocation.Args[2];
            arg4 = (T4)lastInvocation.Args[3];
            arg5 = (T5)lastInvocation.Args[4];
            arg6 = (T6)lastInvocation.Args[5];
            arg7 = (T7)lastInvocation.Args[6];
            arg8 = (T8)lastInvocation.Args[7];
        }
    }

    public class ActionMethod<T1, T2, T3, T4, T5, T6, T7, T8, T9> : ActionMethodBase
    {
        public ActionMethod(StubHelper stubHelper, string methodName) : base(stubHelper, methodName) { }

        public void ToDo(Action<T1, T2, T3, T4, T5, T6, T7, T8, T9> d)
        {
            _stubHelper.SetMethodToInvoke(_methodName, null, d);
        }

        public void GetLastArgs(out T1 arg1, out T2 arg2, out T3 arg3, out T4 arg4, out T5 arg5, out T6 arg6, out T7 arg7, out T8 arg8, out T9 arg9)
        {
            StubInvocation lastInvocation = _stubHelper.GetLastInvocation(_methodName);
            arg1 = (T1)lastInvocation.Args[0];
            arg2 = (T2)lastInvocation.Args[1];
            arg3 = (T3)lastInvocation.Args[2];
            arg4 = (T4)lastInvocation.Args[3];
            arg5 = (T5)lastInvocation.Args[4];
            arg6 = (T6)lastInvocation.Args[5];
            arg7 = (T7)lastInvocation.Args[6];
            arg8 = (T8)lastInvocation.Args[7];
            arg9 = (T9)lastInvocation.Args[8];
        }
    }

    public class FuncMethodBase<TResult>
    {
        protected StubHelper _stubHelper;
        protected string _methodName;

        public FuncMethodBase(StubHelper stubHelper, string methodName)
        {
            _stubHelper = stubHelper;
            _methodName = methodName;
        }

        public void ToReturn(TResult result)
        {
            _stubHelper.SetMethodToReturn(_methodName, null, result);
        }

        public void ToThrow(Exception e)
        {
            _stubHelper.SetMethodToThrow(_methodName, null, e);
        }

        public int GetInvocationCount()
        {
            return _stubHelper.GetInvocations(_methodName).Count;
        }
    }

    public class FuncMethod<TResult> : FuncMethodBase<TResult>
    {
        public FuncMethod(StubHelper stubHelper, string methodName) : base(stubHelper, methodName) { }

        public void ToDo(Func<TResult> d)
        {
            _stubHelper.SetMethodToInvoke(_methodName, null, d);
        }
    }

    public class FuncMethod<T1, TResult> : FuncMethodBase<TResult>
    {
        public FuncMethod(StubHelper stubHelper, string methodName) : base(stubHelper, methodName) { }

        public void ToDo(Func<T1, TResult> d)
        {
            _stubHelper.SetMethodToInvoke(_methodName, null, d);
        }

        public void GetLastArgs(out T1 arg1)
        {
            StubInvocation lastInvocation = _stubHelper.GetLastInvocation(_methodName);
            arg1 = (T1)lastInvocation.Args[0];
        }
    }

    public class FuncMethod<T1, T2, TResult> : FuncMethodBase<TResult>
    {
        public FuncMethod(StubHelper stubHelper, string methodName) : base(stubHelper, methodName) { }

        public void ToDo(Func<T1, T2, TResult> d)
        {
            _stubHelper.SetMethodToInvoke(_methodName, null, d);
        }

        public void GetLastArgs(out T1 arg1, out T2 arg2)
        {
            StubInvocation lastInvocation = _stubHelper.GetLastInvocation(_methodName);
            arg1 = (T1)lastInvocation.Args[0];
            arg2 = (T2)lastInvocation.Args[1];
        }
    }

    public class FuncMethod<T1, T2, T3, TResult> : FuncMethodBase<TResult>
    {
        public FuncMethod(StubHelper stubHelper, string methodName) : base(stubHelper, methodName) { }

        public void ToDo(Func<T1, T2, T3, TResult> d)
        {
            _stubHelper.SetMethodToInvoke(_methodName, null, d);
        }

        public void GetLastArgs(out T1 arg1, out T2 arg2, out T3 arg3)
        {
            StubInvocation lastInvocation = _stubHelper.GetLastInvocation(_methodName);
            arg1 = (T1)lastInvocation.Args[0];
            arg2 = (T2)lastInvocation.Args[1];
            arg3 = (T3)lastInvocation.Args[2];
        }
    }

    public class FuncMethod<T1, T2, T3, T4, TResult> : FuncMethodBase<TResult>
    {
        public FuncMethod(StubHelper stubHelper, string methodName) : base(stubHelper, methodName) { }

        public void ToDo(Func<T1, T2, T3, T4, TResult> d)
        {
            _stubHelper.SetMethodToInvoke(_methodName, null, d);
        }

        public void GetLastArgs(out T1 arg1, out T2 arg2, out T3 arg3, out T4 arg4)
        {
            StubInvocation lastInvocation = _stubHelper.GetLastInvocation(_methodName);
            arg1 = (T1)lastInvocation.Args[0];
            arg2 = (T2)lastInvocation.Args[1];
            arg3 = (T3)lastInvocation.Args[2];
            arg4 = (T4)lastInvocation.Args[3];
        }
    }

    public class FuncMethod<T1, T2, T3, T4, T5, TResult> : FuncMethodBase<TResult>
    {
        public FuncMethod(StubHelper stubHelper, string methodName) : base(stubHelper, methodName) { }

        public void ToDo(Func<T1, T2, T3, T4, T5, TResult> d)
        {
            _stubHelper.SetMethodToInvoke(_methodName, null, d);
        }

        public void GetLastArgs(out T1 arg1, out T2 arg2, out T3 arg3, out T4 arg4, out T5 arg5)
        {
            StubInvocation lastInvocation = _stubHelper.GetLastInvocation(_methodName);
            arg1 = (T1)lastInvocation.Args[0];
            arg2 = (T2)lastInvocation.Args[1];
            arg3 = (T3)lastInvocation.Args[2];
            arg4 = (T4)lastInvocation.Args[3];
            arg5 = (T5)lastInvocation.Args[4];
        }
    }

    public class FuncMethod<T1, T2, T3, T4, T5, T6, TResult> : FuncMethodBase<TResult>
    {
        public FuncMethod(StubHelper stubHelper, string methodName) : base(stubHelper, methodName) { }

        public void ToDo(Func<T1, T2, T3, T4, T5, T6, TResult> d)
        {
            _stubHelper.SetMethodToInvoke(_methodName, null, d);
        }

        public void GetLastArgs(out T1 arg1, out T2 arg2, out T3 arg3, out T4 arg4, out T5 arg5, out T6 arg6)
        {
            StubInvocation lastInvocation = _stubHelper.GetLastInvocation(_methodName);
            arg1 = (T1)lastInvocation.Args[0];
            arg2 = (T2)lastInvocation.Args[1];
            arg3 = (T3)lastInvocation.Args[2];
            arg4 = (T4)lastInvocation.Args[3];
            arg5 = (T5)lastInvocation.Args[4];
            arg6 = (T6)lastInvocation.Args[5];
        }
    }

    public class FuncMethod<T1, T2, T3, T4, T5, T6, T7, TResult> : FuncMethodBase<TResult>
    {
        public FuncMethod(StubHelper stubHelper, string methodName) : base(stubHelper, methodName) { }

        public void ToDo(Func<T1, T2, T3, T4, T5, T6, T7, TResult> d)
        {
            _stubHelper.SetMethodToInvoke(_methodName, null, d);
        }

        public void GetLastArgs(out T1 arg1, out T2 arg2, out T3 arg3, out T4 arg4, out T5 arg5, out T6 arg6, out T7 arg7)
        {
            StubInvocation lastInvocation = _stubHelper.GetLastInvocation(_methodName);
            arg1 = (T1)lastInvocation.Args[0];
            arg2 = (T2)lastInvocation.Args[1];
            arg3 = (T3)lastInvocation.Args[2];
            arg4 = (T4)lastInvocation.Args[3];
            arg5 = (T5)lastInvocation.Args[4];
            arg6 = (T6)lastInvocation.Args[5];
            arg7 = (T7)lastInvocation.Args[6];
        }
    }

    public class FuncMethod<T1, T2, T3, T4, T5, T6, T7, T8, TResult> : FuncMethodBase<TResult>
    {
        public FuncMethod(StubHelper stubHelper, string methodName) : base(stubHelper, methodName) { }

        public void ToDo(Func<T1, T2, T3, T4, T5, T6, T7, T8, TResult> d)
        {
            _stubHelper.SetMethodToInvoke(_methodName, null, d);
        }

        public void GetLastArgs(out T1 arg1, out T2 arg2, out T3 arg3, out T4 arg4, out T5 arg5, out T6 arg6, out T7 arg7, out T8 arg8)
        {
            StubInvocation lastInvocation = _stubHelper.GetLastInvocation(_methodName);
            arg1 = (T1)lastInvocation.Args[0];
            arg2 = (T2)lastInvocation.Args[1];
            arg3 = (T3)lastInvocation.Args[2];
            arg4 = (T4)lastInvocation.Args[3];
            arg5 = (T5)lastInvocation.Args[4];
            arg6 = (T6)lastInvocation.Args[5];
            arg7 = (T7)lastInvocation.Args[6];
            arg8 = (T8)lastInvocation.Args[7];
        }
    }

    public class FuncMethod<T1, T2, T3, T4, T5, T6, T7, T8, T9, TResult> : FuncMethodBase<TResult>
    {
        public FuncMethod(StubHelper stubHelper, string methodName) : base(stubHelper, methodName) { }

        public void ToDo(Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TResult> d)
        {
            _stubHelper.SetMethodToInvoke(_methodName, null, d);
        }

        public void GetLastArgs(out T1 arg1, out T2 arg2, out T3 arg3, out T4 arg4, out T5 arg5, out T6 arg6, out T7 arg7, out T8 arg8, out T9 arg9)
        {
            StubInvocation lastInvocation = _stubHelper.GetLastInvocation(_methodName);
            arg1 = (T1)lastInvocation.Args[0];
            arg2 = (T2)lastInvocation.Args[1];
            arg3 = (T3)lastInvocation.Args[2];
            arg4 = (T4)lastInvocation.Args[3];
            arg5 = (T5)lastInvocation.Args[4];
            arg6 = (T6)lastInvocation.Args[5];
            arg7 = (T7)lastInvocation.Args[6];
            arg8 = (T8)lastInvocation.Args[7];
            arg9 = (T9)lastInvocation.Args[8];
        }
    }

    public delegate void Action();
    public delegate void Action<T1>(T1 arg1);
    public delegate void Action<T1, T2>(T1 arg1, T2 arg2);
    public delegate void Action<T1, T2, T3>(T1 arg1, T2 arg2, T3 arg3);
    public delegate void Action<T1, T2, T3, T4>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
    public delegate void Action<T1, T2, T3, T4, T5>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5);
    public delegate void Action<T1, T2, T3, T4, T5, T6>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6);
    public delegate void Action<T1, T2, T3, T4, T5, T6, T7>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7);
    public delegate void Action<T1, T2, T3, T4, T5, T6, T7, T8>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8);
    public delegate void Action<T1, T2, T3, T4, T5, T6, T7, T8, T9>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9);

    public delegate TResult Func<TResult>();
    public delegate TResult Func<T1, TResult>(T1 arg1);
    public delegate TResult Func<T1, T2, TResult>(T1 arg1, T2 arg2);
    public delegate TResult Func<T1, T2, T3, TResult>(T1 arg1, T2 arg2, T3 arg3);
    public delegate TResult Func<T1, T2, T3, T4, TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
    public delegate TResult Func<T1, T2, T3, T4, T5, TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5);
    public delegate TResult Func<T1, T2, T3, T4, T5, T6, TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6);
    public delegate TResult Func<T1, T2, T3, T4, T5, T6, T7, TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7);
    public delegate TResult Func<T1, T2, T3, T4, T5, T6, T7, T8, TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8);
    public delegate TResult Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9);
}
